package mapEditor;

import context.*;

import mainFrame.MainFrame;
import mainFrame.PrintDialog;
import mainFrame.StatusLine;
import model2D.Model2D;

import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.JSeparator;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.ButtonGroup;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;

import org.json.JSONException;

import util.ButtonTabComponent;
import util.EditorProperties;
import util.FillStyle;
import util.FontStyle;
import util.StrokeStyle;

import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

// ***************************************************************************
// *** CLASS: MapEditor
// ***************************************************************************
public class MapEditor extends MainFrame implements Context.Constants
{ //private static final boolean DEBUG=true; // Overriding Context.Constants.DEBUG
  static final String TAG="mapEditor.MapEditor";


  // *************************************************************************
  // *** MAIN ENTRYPOINT
  // *************************************************************************
  public static void main(String s[]) { new MapEditor(); }
  private MapEditor() // NOTE: Private Constructor
  {
	if(DEBUG) Log.d(TAG,"MapEditor STARTED: UserName="+EditorProperties.getUserName());
	if(DEBUG) Log.d(TAG,"MapEditor STARTED: UserHome="+EditorProperties.getUserHomeDirectory());
	if(DEBUG) Log.d(TAG,"MapEditor STARTED: WorkSpace="+EditorProperties.getWorkSpaceDirectory());

	EditorProperties.setWorkSpaceDirectory(EditorProperties.getWorkSpaceDirectory()); // TODO: TEST !!!!
	
    controlPanel=new MapControlPanel();
    statusLine=new StatusLine();

    tabbedMap=new JTabbedPane();
    tabbedMap.addChangeListener(new ChangeListener()
    { public void stateChanged(ChangeEvent e)
      { if(DEBUG) Log.d(TAG,"mapTabChanged: "+e);
        JScrollPane scrollPane=(JScrollPane)tabbedMap.getSelectedComponent();
        if(scrollPane!=null)
        { JViewport viewport=scrollPane.getViewport();
          currentDrawPanel=(DrawMapPanel)viewport.getView();
          ((DrawMapPanel)currentDrawPanel).setSelected();
        } else currentDrawPanel=null;
      }
    });

    tabbedTable=new JTabbedPane();
    tabbedTable.addChangeListener(new ChangeListener()
    { public void stateChanged(ChangeEvent e)
      { if(DEBUG) Log.d(TAG,"tableTabChanged: "+e);
        Component selected=tabbedTable.getSelectedComponent();
        selectedTable=(selected instanceof MapTablePane)?(MapTablePane)selected:null;
      }
     });
    
    triPane=new TriPane(controlPanel,tabbedMap,tabbedTable);

    frame=new JFrame("Map Editor");
    frame.addWindowListener(new WindowAdapter()
    { public void windowClosing(WindowEvent e) {System.exit(0);}  });
    frame.getContentPane().add("Center",triPane);
    frame.getContentPane().add("South",statusLine);

    JMenuBar menuBar=new JMenuBar();
    frame.setJMenuBar(menuBar);
    menuBar.add(makeFileMenu());
    menuBar.add(makeMapMenu());
    menuBar.add(makeZoomMenu());
    menuBar.add(makeStyleMenu());
    menuBar.add(makeHelpMenu());
    menuBar.add(new JSeparator(SwingConstants.VERTICAL));

    frame.pack();
    frame.setVisible(true);
  }
  
  private void openMapComponent(Reader reader) throws IOException,JSONException
  { // NOTE: reader may be null meaning a new Component
	currentDrawPanel=new DrawMapPanel(reader);
    String name=currentDrawPanel.getName();
    JScrollPane scrollPane=new JScrollPane(currentDrawPanel);
    ((DrawMapPanel)currentDrawPanel).setScrollPane(scrollPane);  
    tabbedMap.addTab(name,null,scrollPane,"Tip for '"+name+"'tab");
	tabbedMap.setSelectedComponent(scrollPane);
    // TODO: TEST - Add Close button on tab
    { int i=tabbedMap.getSelectedIndex();
      tabbedMap.setTabComponentAt(i,new ButtonTabComponent(tabbedMap));
    }    
    openTable();
  }
  
  private void openTable()
  { Model2D objectModel=((DrawMapPanel)currentDrawPanel).getObjectModel();
	String name=objectModel.getName();
    MapTablePane tablePane=new MapTablePane(objectModel);
    selectedTable=tablePane;
    tabbedTable.addTab(name,null,tablePane,"Tip for '"+name+"'tab");
    tabbedTable.setSelectedComponent(tablePane);
    
    // TODO: TEST
    { int i=tabbedTable.getSelectedIndex();
      tabbedTable.setTabComponentAt(i,new ButtonTabComponent(tabbedTable));
    }    

  }
  
  private void openDialog()
  { try
    { if(DEBUG) Log.d(TAG,"openDialog");
      final JFileChooser fc=new JFileChooser();
      File dir=new File(EditorProperties.getWorkSpaceDirectory());//("C:/Kart");
//      fff.createNewFile();
      dir.mkdirs();
      fc.setCurrentDirectory(dir);
      fc.setSelectedFile(new File("Default.json"));
      int returnVal = fc.showOpenDialog(frame);
      if(returnVal!=JFileChooser.APPROVE_OPTION)
      { if(DEBUG) Log.d(TAG,"Open command cancelled by user.");
        return;
      }
      File selectedFile=fc.getSelectedFile();
      if(DEBUG) Log.d(TAG,"openDialog: Selected File: "+selectedFile.getAbsolutePath()+", Name: "+selectedFile.getName()+".");
      FileInputStream fileInputStream=new FileInputStream(selectedFile);
      InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"UTF-8");
      BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
      openMapComponent(bufferedReader);
      bufferedReader.close();
      
    } catch (Exception e) { Log.e(TAG,"openDialog: ",e); }
  }
  
  private void saveAsDialog()
  { try
    { if(DEBUG) Log.d(TAG,"saveAsDialog");
      final JFileChooser fileChooser=new JFileChooser();
      File dir=new File(EditorProperties.getWorkSpaceDirectory());//("C:/Kart");
      dir.mkdirs();
      fileChooser.setCurrentDirectory(dir);
      fileChooser.setSelectedFile(new File("Default.json"));
      int returnVal=fileChooser.showSaveDialog(frame);
      if(returnVal!=JFileChooser.APPROVE_OPTION)
      { if(DEBUG) Log.d(TAG,"Open command cancelled by user.");
        return;
      }
      File selectedFile=fileChooser.getSelectedFile();
      //This is where a real application would open the file.
      if(DEBUG) Log.d(TAG,"Selected File: "+selectedFile.getAbsolutePath()+", Name: "+selectedFile.getName()+".");
      selectedFile.createNewFile();
      
      FileOutputStream fileOutputStream=new FileOutputStream(selectedFile);
      OutputStreamWriter outputStreamWriter=new OutputStreamWriter(fileOutputStream,"UTF-8");
      BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter); 
      ((DrawMapPanel)currentDrawPanel).writeJSONFile(bufferedWriter);  
      bufferedWriter.close();
    } catch (Exception e) { Log.e(TAG,"saveAsDialog: ",e); }
  }

  // ***************************************************************************
  // *** MENUES Utilities
  // ***************************************************************************

  private void addItem(JMenu menu,String ident,ActionListener action)
  { addItem(menu,null,ident,action); }

  private void addItem
  (JMenu menu,ButtonGroup group,String ident,ActionListener action)
  { JMenuItem itm=new JMenuItem(ident);
    if(action==null) itm.setEnabled(false);
    else itm.addActionListener(action);
    if(group!=null) group.add(itm);
    menu.add(itm);
  }

//  private void addCheckBoxItem
//  (JMenu menu,ButtonGroup group,String ident,ActionListener action)
//  { JCheckBoxMenuItem itm=new JCheckBoxMenuItem(ident);
//    if(action==null) itm.setEnabled(false);
//    else itm.addActionListener(action);
//    if(group!=null) group.add(itm);
//    menu.add(itm);
//  }

  // ******************************************************************
  // *** Fele Menue. Methods
  // ******************************************************************
  public JMenu makeFileMenu()
  { JMenu file=new JMenu("File");
    addItem(file,"New",new ActionListener()
    { public void actionPerformed(ActionEvent evt)
      { try { openMapComponent(null); }
        catch (Exception e) { Log.e(TAG,"File/New: ",e); }  
      }
    });
    addItem(file,"Open",new ActionListener()
    { public void actionPerformed(ActionEvent e) { openDialog(); } });
    addItem(file,"Close",closeCmnd);
    addItem(file,"Close All",null);
    file.addSeparator();
    addItem(file,"Save",null);
    addItem(file,"Save As",new ActionListener()
    { public void actionPerformed(ActionEvent e) { saveAsDialog(); } });
    addItem(file,"Save All",null);
    file.addSeparator();
    addItem(file,"Print",printCmnd);
    file.addSeparator();
    addItem(file,"Exit",exitCmnd);
    return(file);
  }

  private ActionListener closeCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { int result=JOptionPane.showConfirmDialog(frame,"Save file before closing?");
      if(result == JOptionPane.YES_OPTION) saveAsDialog();
      else if(result == JOptionPane.NO_OPTION) ;//frame.dispose(); ???
    }
  };

  private ActionListener exitCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { System.exit(0); }
  };

  private ActionListener printCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { PrintDialog printDialog=new PrintDialog();
	  printDialog.append(((DrawMapPanel)currentDrawPanel));
	  printDialog.print();
	}
  };
  
  // ***************************************************************************
  // *** Map Menu: Methods
  // ***************************************************************************
  private JMenu makeMapMenu()
  { JMenu map=new JMenu("Map");
    addItem(map,"Background",new ActionListener()
    { public void actionPerformed(ActionEvent e)
      {	((DrawMapPanel)currentDrawPanel).getObjectModel().backgroudImageDialog(); }
    });
    addItem(map,"Calibrate Grid",new ActionListener()
    { public void actionPerformed(ActionEvent e)
      { ((DrawMapPanel)currentDrawPanel).getObjectModel().getGrid().new GridCalibratingDialog(); }
    });
    return(map);
  }

  // ***************************************************************************
  // *** Zoom Menu: Methods
  // ***************************************************************************

  private JMenu makeZoomMenu()
  { JMenu zoom=new JMenu("Zoom");
    addItem(zoom,"Zoom In",new ActionListener()
    { public void actionPerformed(ActionEvent e)
      { ((DrawMapPanel)currentDrawPanel).zoom(true); }
    });
    addItem(zoom,"Zoom Out",new ActionListener()
    { public void actionPerformed(ActionEvent e)
      { ((DrawMapPanel)currentDrawPanel).zoom(false); }
    });
    zoom.addSeparator();
    addItem(zoom,"Zoom Reset",new ActionListener()
    { public void actionPerformed(ActionEvent e)
      { ((DrawMapPanel)currentDrawPanel).zoomReset(); }
    });
    return(zoom);
  }

  // ***************************************************************************
  // *** Style Menu: Methods
  // ***************************************************************************
  private JMenu makeStyleMenu()
  { JMenu help=new JMenu("Styling");
    addItem(help,"Font",fontCmnd);
    addItem(help,"Stroke",strokeCmnd);
    addItem(help,"Fill",fillCmnd);
    return(help);
  }
  private FontStyle.FontDialog currentFontDialog;
  private StrokeStyle.StrokeDialog currentStrokeDialog;
  private FillStyle.FillDialog currentFillDialog;
  private ActionListener fontCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { if(currentFontDialog!=null) currentFontDialog.cancel();
      currentFontDialog=currentFont.new FontDialog(currentStroke,true);
    }
  };
  private ActionListener strokeCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { if(currentStrokeDialog!=null) currentStrokeDialog.cancel();
      currentStrokeDialog=currentStroke.new StrokeDialog(true);
    }
  };
  private ActionListener fillCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { if(currentFillDialog!=null) currentFillDialog.cancel();
      currentFillDialog=currentFill.new FillDialog(currentStroke,true);
    }
  };

  // ***************************************************************************
  // *** Help Menu: Methods
  // ***************************************************************************
  private JMenu makeHelpMenu()
  { JMenu help=new JMenu("Help");
    addItem(help,"Help",null);
    addItem(help,"About",aboutCmnd);
    return(help);
  }

  private ActionListener aboutCmnd=new ActionListener()
  { public void actionPerformed(ActionEvent e)
    { Log.NOT_IMPLEMENTED(TAG,"About Map Editor......about....."); }
  };

}
